/*
* Copyright [2011] [Ilya Rudakov]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var chain;

/**
*  var chain = $.Chain();
*  chain.addOperation(openWaitWindow, []);
*
*  chain.addAsyncOperation($.getJSON, function(categories) {
*  		//Do some things
*  }, ['some arg 1', 'some arg 2']);
*            
*  chain.addOperation(closeWaitWindow, []);
*  chain.addOperation(function() {
*  		//Do some things
*  }, []);
*  chain.invoke();
*
**/
function Chain() {
    this.queue = [];
    this.processing = false;
    this.lastTimeOutID = 0;
}

Chain.prototype = {

    addOperation: function(operation, args) {
        this.queue.push({
            operation:operation,
            arguments:args != null ? args : [],
            isSync: true
        });
    },

    addAsyncOperation: function(operation, callback, args) {
        if(args == null) {
            args = [];
        }
        args.push(this.internalResultHandler);
        this.queue.push({
            operation:operation,
            callback:callback,
            arguments: args,
            isSync: false
        });
        return this;
    },

    invokeNext: function() {
        if(this.queue.length == 0) {
            this.processing = false;
            return;
        }

        var data = this.queue[0];
        data.operation.apply(this, data.arguments);
        if(data.isSync) {
            this.lastTimeOutID = setTimeout(this.internalResultHandler, 1);
        }
    },

    internalResultHandler: function(args, errorSuccess) {
        var lastTimeOutID = chain.lastTimeOutID;
        if (lastTimeOutID != 0) {
            clearTimeout(lastTimeOutID);
            lastTimeOutID = 0;
        }
        var queue = chain.queue;
        var data = queue[0];
        var callback = data.callback;
        if(callback != null) {
            callback.call(this, args);
        }
        queue.shift();
        chain.invokeNext();    
    },

    invoke: function() {
        this.processing = true;
        this.invokeNext();
    }
};
